/* Use ltgen */

#ifndef SRC_LOGPRINT_H_
#define SRC_LOGPRINT_H_

#include "src/ltbase.h"
#include "src/ltcolor.h"
#include "src/ltpanic.h"
#include "src/ltprint.h"

typedef enum {
    ltlog_Fatal,
    ltlog_Error,
    ltlog_Warn,
    ltlog_Info,
    ltlog_Debug,
} ltlog_Level;

lt_ForceInline char const*
ltlog_LevelName(ltlog_Level level) {
    static char const* name[] = {
        [ltlog_Fatal] = "FATAL", //
        [ltlog_Error] = "ERROR", //
        [ltlog_Warn] = "WARN ",
        [ltlog_Info] = "INFO ", //
        [ltlog_Debug] = "DEBUG",
    };
    return name[level];
}

lt_ForceInline char const*
ltlog_LevelColor(ltlog_Level level) {
    static char const* name[] = {
        [ltlog_Fatal] = ltcolor_kColorMagenta, //
        [ltlog_Error] = ltcolor_kColorRed,     //
        [ltlog_Warn] = ltcolor_kColorYellow,
        [ltlog_Info] = ltcolor_kColorCyan, //
        [ltlog_Debug] = "",
    };
    return name[level];
}

ltlog_Level ltlog_GetLevel(void);
ltlog_Level ltlog_SetLevel(ltlog_Level level);

#define ltlog_Todo(M_message)                                                  \
    ltlog_Log2(Fatal, "TODO: " M_message, "file", String(__FILE__), "line",    \
               U32(__LINE__))

#define ltlog__ShowExpr(M_desc, M_x)                                           \
    ltprint_EPrint_String(", " ltcolor_kColorGreen);                           \
    ltprint_EPrint_String(M_desc);                                             \
    ltprint_EPrint_String(": " ltcolor_kColorReset);                           \
    ltprint_EPrint_##M_x

#define ltlog__Start(M_level, M_text)                                          \
    if (!ltlog__IsOn_##M_level())                                              \
        break;                                                                 \
    fprintf(stderr, "%s[%s] %s" ltcolor_kColorReset,                           \
            ltlog_LevelColor(ltlog_##M_level),                                 \
            ltlog_LevelName(ltlog_##M_level), M_text)

lt_ForceInline bool
ltlog_IsOn(ltlog_Level level) {
    return level <= ltlog_GetLevel();
}

#define ltlog__IsOn_Fatal() (true)
#define ltlog__IsOn_Error() ltlog_IsOn(ltlog_Error)
#define ltlog__IsOn_Warn() ltlog_IsOn(ltlog_Warn)
#define ltlog__IsOn_Info() ltlog_IsOn(ltlog_Info)
#define ltlog__IsOn_Debug() ltlog_IsOn(ltlog_Debug)

lt_ForceInline void
ltlog__End_NoPanic(void) {
    fprintf(stderr, ltcolor_kColorReset "\n");
}

lt_NoReturn lt_ForceInline void
ltlog__End_Panic(void) {
    ltlog__End_NoPanic();
    lt_Panic("ltlog write a fatal level message");
}

#define ltlog__End_Fatal() ltlog__End_Panic()
#define ltlog__End_Error() ltlog__End_NoPanic()
#define ltlog__End_Warn() ltlog__End_NoPanic()
#define ltlog__End_Info() ltlog__End_NoPanic()
#define ltlog__End_Debug() ltlog__End_NoPanic()

int ltgen_gen_ltlog_Logs(void);
/* ltgen ltlog_Logs */
/* clang-format off */
#define ltlog_Log0(M_level, M_text) \
    do { \
        ltlog__Start(M_level, M_text); \
        \
        ltlog__End_##M_level(); \
    } while (0)

#define ltlog_Log1(M_level, M_text, M_l1, M_x1) \
    do { \
        ltlog__Start(M_level, M_text); \
        \
        ltlog__ShowExpr(M_l1, M_x1); \
        \
        ltlog__End_##M_level(); \
    } while (0)

#define ltlog_Log2(M_level, M_text, M_l1, M_x1, M_l2, M_x2) \
    do { \
        ltlog__Start(M_level, M_text); \
        \
        ltlog__ShowExpr(M_l1, M_x1); \
        ltlog__ShowExpr(M_l2, M_x2); \
        \
        ltlog__End_##M_level(); \
    } while (0)

#define ltlog_Log3(M_level, M_text, M_l1, M_x1, M_l2, M_x2, M_l3, M_x3) \
    do { \
        ltlog__Start(M_level, M_text); \
        \
        ltlog__ShowExpr(M_l1, M_x1); \
        ltlog__ShowExpr(M_l2, M_x2); \
        ltlog__ShowExpr(M_l3, M_x3); \
        \
        ltlog__End_##M_level(); \
    } while (0)

#define ltlog_Log4(M_level, M_text, M_l1, M_x1, M_l2, M_x2, M_l3, M_x3, M_l4, M_x4) \
    do { \
        ltlog__Start(M_level, M_text); \
        \
        ltlog__ShowExpr(M_l1, M_x1); \
        ltlog__ShowExpr(M_l2, M_x2); \
        ltlog__ShowExpr(M_l3, M_x3); \
        ltlog__ShowExpr(M_l4, M_x4); \
        \
        ltlog__End_##M_level(); \
    } while (0)

#define ltlog_Log5(M_level, M_text, M_l1, M_x1, M_l2, M_x2, M_l3, M_x3, M_l4, M_x4, M_l5, M_x5) \
    do { \
        ltlog__Start(M_level, M_text); \
        \
        ltlog__ShowExpr(M_l1, M_x1); \
        ltlog__ShowExpr(M_l2, M_x2); \
        ltlog__ShowExpr(M_l3, M_x3); \
        ltlog__ShowExpr(M_l4, M_x4); \
        ltlog__ShowExpr(M_l5, M_x5); \
        \
        ltlog__End_##M_level(); \
    } while (0)

#define ltlog_Log6(M_level, M_text, M_l1, M_x1, M_l2, M_x2, M_l3, M_x3, M_l4, M_x4, M_l5, M_x5, M_l6, M_x6) \
    do { \
        ltlog__Start(M_level, M_text); \
        \
        ltlog__ShowExpr(M_l1, M_x1); \
        ltlog__ShowExpr(M_l2, M_x2); \
        ltlog__ShowExpr(M_l3, M_x3); \
        ltlog__ShowExpr(M_l4, M_x4); \
        ltlog__ShowExpr(M_l5, M_x5); \
        ltlog__ShowExpr(M_l6, M_x6); \
        \
        ltlog__End_##M_level(); \
    } while (0)

#define ltlog_Log7(M_level, M_text, M_l1, M_x1, M_l2, M_x2, M_l3, M_x3, M_l4, M_x4, M_l5, M_x5, M_l6, M_x6, M_l7, M_x7) \
    do { \
        ltlog__Start(M_level, M_text); \
        \
        ltlog__ShowExpr(M_l1, M_x1); \
        ltlog__ShowExpr(M_l2, M_x2); \
        ltlog__ShowExpr(M_l3, M_x3); \
        ltlog__ShowExpr(M_l4, M_x4); \
        ltlog__ShowExpr(M_l5, M_x5); \
        ltlog__ShowExpr(M_l6, M_x6); \
        ltlog__ShowExpr(M_l7, M_x7); \
        \
        ltlog__End_##M_level(); \
    } while (0)

/* clang-format on */
/* ltgen_End */

#endif // SRC_LOGPRINT_H_
